#include "MBTriangleSightTriangle.h"
#include "MBDataTypes.h"

#include "OptTriTri.h"
#include "Tribox3.h"

const MBuint P0 = 0u;
const MBuint P1 = 1u;

const MBuint X = 0u;
const MBuint Y = 1u;
const MBuint Z = 2u;

const MBuint NUM_PLANES = 2u;

/**
  * Constructs a new MBTriangleSightTriangle with the given parameters
  *
  * @param edgePoints const pointer to an array with two points in 3D space
  * @param cameraPosition position of the camera in 3D space
  */
MBTriangleSightTriangle::MBTriangleSightTriangle( const MBVec3 *edgePoints, const MBVec3 &cameraPosition ) :
	mP0( edgePoints[P0] ),
	mP1( edgePoints[P1] ),
	mCamPos( cameraPosition )
{
	MBVec3 normal = MBVec3::Cross( edgePoints[P1] - cameraPosition, edgePoints[P0] - cameraPosition );
	normal.Normalize();

	mPlanes[P1_P0_CAMPOS].SetNormalAndPoint( normal, cameraPosition );
	mPlanes[P1_P0_CAMPOS_REVERSE].SetNormalAndPoint( -normal, cameraPosition );
}

/**
  * Returns true if this MBTriangleSightTriangle intersects with the axis
  * aligned bounding box defined by the parameters, false otherwise
  *
  * @param boxMin minimum point of the axis aligned bounding box
  * @param boxMax maximum point of the axis aligned bounding box
  * @return true if this MBTriangleSightTriangle intersects with the axis aligned bounding box defined by the parameters, false otherwise
  */
bool MBTriangleSightTriangle::IsIntersectingWithAxisAlignedBox( const MBVec3 &boxMin, const MBVec3 &boxMax ) const
{
	for (MBuint i = 0; i < NUM_PLANES; i++)
	{
		// is the positive vertex outside?
		// (this implies that the box is outside the whole frustum)
		if (mPlanes[i].IsPositiveVertexOfAxisAlignedBoxOutside( boxMin, boxMax ))
		{
			return false;
		}
	}

	MBVec3 mid_point = (boxMin + boxMax) * 0.5;
	MBVec3 box_h = (boxMax - boxMin) * 0.5;

	const double *tri_vertices[] = { &mP0[X], &mP1[X], &mCamPos[X] };

	return (triBoxOverlap( &mid_point[X], &box_h[X], tri_vertices ) == 1);
}

/**
  * Returns true if this MBTriangleSightTriangle intersects with the triangle
  * defined by the parameter, false otherwise
  *
  * @param trianglePoints const pointer to an array with three elements containing the points of a triangle
  * @return true if this MBTriangleSightTriangle intersects with the triangle defined by the parameter, false otherwise
  */
bool MBTriangleSightTriangle::IsIntersectingWithTriangle( const MBVec3 *trianglePoints ) const
{
	// 	P1_P0_CAMPOS
	if (NoDivTriTriIsect( &mP1[X], &mP0[X], &mCamPos[X],
		&trianglePoints[0][X], &trianglePoints[1][X], &trianglePoints[2][X] ))
	{
		return true;
	}

	return false;
}